import {CollUtil} from '../../../utils/CollUtil.js';
import {StrUtil} from '../../../utils/StrUtil.js';
import {getProjectOpsFile} from '../../../utils/OpsFile.js';
import {newGitLabClient} from '../../../utils/GitLabClient.js';

export const mergeMixin = {
    async handleRefreshCommand() {
        this.logger.step(1, '刷新当前目录下发布单项目和依赖发布单项目信息');
        this.assignProjectOpsFile(getProjectOpsFile());
        let url = await this.projectOpsFile.read("flow.url");
        if (StrUtil.notNull(url)) {
            this.logger.info('刷新普通发布单内容');
            await this.handleInitCommand(url, ['PWD'])
        }
        url = await this.projectOpsFile.read("support.url");
        if (StrUtil.notNull(url)) {
            this.logger.info('刷新依赖发布单内容');
            await this.handleInitCommand(url, ['PWD'])
        }
        this.logger.success('项目信息刷新完成');
    },

    async handleMergeToCommand(rawTarget) {
        const targetInput = this.normalizeString(rawTarget);
        if (!targetInput) {
            throw new Error('请提供目标发布单链接或目标分支，例如 https://vops.hszq8.com/app/flow/flow_detail?flow_type=story&flow_id=1234');
        }
        if (!this.looksLikeUrl(targetInput)) {
            await this.handleMergeToBranchTarget(targetInput);
            return;
        }
        let target;
        try {
            target = this.parseFlowDetailUrl(targetInput);
        } catch (error) {
            throw new Error(`目标发布单链接解析失败: ${error.message}`);
        }
        this.logger.step(1, `目标发布单 ${target.flowId} (${target.flowType})`);

        this.assignProjectOpsFile(getProjectOpsFile());
        const currentFlowUrlRaw = this.projectOpsFile.read('flow.url');
        const currentFlowUrl = this.normalizeString(currentFlowUrlRaw);
        if (!currentFlowUrl) {
            throw new Error('未在当前目录的 ops.conf 中找到 flow.url，请在发布单项目目录执行该命令');
        }

        let current;
        try {
            current = this.parseFlowDetailUrl(currentFlowUrl);
        } catch (error) {
            throw new Error(`当前发布单链接解析失败: ${error.message}`);
        }
        this.logger.info(`当前发布单 ${current.flowId} (${current.flowType})`);

        this.logger.step(2, '拉取目标发布单项目列表');
        await this.ensureOpsClient(false);
        const targetApps = await this.opsClient.getAppAndBranch(target.flowId, target.flowType);
        if (CollUtil.isEmptyArray(targetApps)) {
            this.logger.warn('目标发布单未包含应用信息，跳过自动合并配置');
            return;
        }
        this.logger.info(`目标发布单共 ${targetApps.length} 个项目，开始比对`);

        const updates = [];
        const skipped = [];
        const applyMapping = async ({gitPathKey, branchKey, appLabel, targetBranch, typeLabel}) => {
            const gitPath = this.normalizeString(await this.projectOpsFile.read(gitPathKey));
            if (!gitPath) {
                const reason = `${typeLabel}${appLabel} 未配置 git.path`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const currentBranch = this.normalizeString(await this.projectOpsFile.read(branchKey));
            if (!currentBranch) {
                const reason = `${typeLabel}${appLabel} 未配置 source.branch`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const desiredBranch = this.normalizeString(targetBranch);
            if (!desiredBranch) {
                const reason = `${typeLabel}${appLabel} 缺少目标分支`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const key = `git_merge.auto_merge_${gitPath}_${currentBranch}`;
            await this.projectOpsFile.write(key, desiredBranch);
            updates.push({
                app: appLabel,
                gitPath,
                currentBranch,
                targetBranch: desiredBranch,
                typeLabel
            });
        };

        for (const item of targetApps) {
            const appName = this.normalizeString(item.app);
            const targetBranch = this.normalizeString(item.name);
            if (!appName) {
                continue;
            }
            await applyMapping({
                gitPathKey: `flow.${appName}.path`,
                branchKey: `flow.${appName}.source.branch`,
                appLabel: appName,
                targetBranch,
                typeLabel: '应用 '
            });

            if (Array.isArray(item.plugin_list)) {
                for (const plugin of item.plugin_list) {
                    const pluginApp = this.normalizeString(plugin.app);
                    const pluginBranch = this.normalizeString(plugin.name);
                    if (!pluginApp) {
                        continue;
                    }
                    await applyMapping({
                        gitPathKey: `flow_jz_plugin.${pluginApp}.path`,
                        branchKey: `flow_jz_plugin.${pluginApp}.source.branch`,
                        appLabel: pluginApp,
                        targetBranch: pluginBranch,
                        typeLabel: `插件(${appName}) `
                    });
                }
            }
        }

        if (updates.length === 0) {
            this.logger.warn('未找到匹配的应用，未生成任何自动合并配置');
            if (skipped.length > 0) {
                this.logger.warn(`跳过原因：${skipped.join('；')}`);
            }
            return;
        }

        this.logger.step(3, `写入自动合并配置，共 ${updates.length} 条`);
        for (const update of updates) {
            this.logger.info(`${update.typeLabel}${update.app}: ${update.currentBranch} -> ${update.targetBranch} (${update.gitPath})`);
        }
        this.logger.success('自动合并映射写入完成，后续构建将使用目标发布单分支');
        if (skipped.length > 0) {
            this.logger.warn(`以下项目未处理：${skipped.join('；')}`);
        }
    },

    async handleMergeToBranchTarget(targetBranchInput) {
        const targetBranch = this.normalizeString(targetBranchInput);
        if (!targetBranch) {
            throw new Error('目标分支名称不能为空');
        }

        this.logger.step(1, `目标分支 ${targetBranch}`);
        this.assignProjectOpsFile(getProjectOpsFile());
        const currentFlowUrlRaw = this.projectOpsFile.read('flow.url');
        const currentFlowUrl = this.normalizeString(currentFlowUrlRaw);
        if (!currentFlowUrl) {
            throw new Error('未在当前目录的 ops.conf 中找到 flow.url，请在发布单项目目录执行该命令');
        }
        try {
            const current = this.parseFlowDetailUrl(currentFlowUrl);
            this.logger.info(`当前发布单 ${current.flowId} (${current.flowType})`);
        } catch (error) {
            this.logger.warn(`当前发布单链接解析失败: ${error.message}`);
        }

        const flowAppNames = await this.projectOpsFile.readList('flow.app.names');
        if (CollUtil.isEmptyArray(flowAppNames)) {
            throw new Error('当前发布单未配置应用信息，无法生成自动合并配置');
        }

        await this.ensureOpsClient(false);
        this.logger.step(2, `校验远端分支并匹配 ${flowAppNames.length} 个基座应用`);

        const updates = [];
        const skipped = [];
        const applyBranchMapping = async ({gitPathKey, branchKey, opsNameKey, appLabel, typeLabel}) => {
            let gitPath = this.normalizeString(await this.projectOpsFile.read(gitPathKey));
            if (!gitPath && gitPathKey.endsWith('.path')) {
                const fallbackKey = `${gitPathKey.slice(0, -5)}git.path`;
                gitPath = this.normalizeString(await this.projectOpsFile.read(fallbackKey));
            }
            if (!gitPath) {
                const reason = `${typeLabel}${appLabel} 未配置 git.path`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const currentBranch = this.normalizeString(await this.projectOpsFile.read(branchKey));
            if (!currentBranch) {
                const reason = `${typeLabel}${appLabel} 未配置 source.branch`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const opsName = this.normalizeString(await this.projectOpsFile.read(opsNameKey)) || appLabel;
            let branchExists = false;
            try {
                const revResponse = await this.opsClient.revs(opsName, targetBranch);
                branchExists = Array.isArray(revResponse) && revResponse.length > 0;
            } catch (error) {
                this.logger.debug?.(`检查远端分支失败 ${opsName}:${targetBranch} - ${error.message}`);
            }
            if (!branchExists) {
                const reason = `${typeLabel}${appLabel} 远端未找到分支 ${targetBranch}`;
                this.logger.warn(`${reason}，跳过`);
                skipped.push(reason);
                return;
            }
            const key = `git_merge.auto_merge_${gitPath}_${currentBranch}`;
            await this.projectOpsFile.write(key, targetBranch);
            updates.push({
                app: appLabel,
                gitPath,
                currentBranch,
                targetBranch,
                typeLabel
            });
        };

        for (const baseApp of flowAppNames) {
            const appName = this.normalizeString(baseApp);
            if (!appName) {
                continue;
            }
            await applyBranchMapping({
                gitPathKey: `flow.${appName}.path`,
                branchKey: `flow.${appName}.source.branch`,
                opsNameKey: `flow.${appName}.opsName`,
                appLabel: appName,
                typeLabel: '应用 '
            });

            const pluginNames = await this.projectOpsFile.readList(`flow_jz.${appName}.plugins`);
            if (CollUtil.isEmptyArray(pluginNames)) {
                continue;
            }
            for (const plugin of pluginNames) {
                const pluginApp = this.normalizeString(plugin);
                if (!pluginApp) {
                    continue;
                }
                await applyBranchMapping({
                    gitPathKey: `flow_jz_plugin.${pluginApp}.path`,
                    branchKey: `flow_jz_plugin.${pluginApp}.source.branch`,
                    opsNameKey: `flow_jz_plugin.${pluginApp}.opsName`,
                    appLabel: pluginApp,
                    typeLabel: `插件(${appName}) `
                });
            }
        }

        if (updates.length === 0) {
            this.logger.warn('未生成任何自动合并配置');
            if (skipped.length > 0) {
                this.logger.warn(`跳过原因：${skipped.join('；')}`);
            }
            return;
        }

        this.logger.step(3, `写入自动合并配置，共 ${updates.length} 条`);
        for (const update of updates) {
            this.logger.info(`${update.typeLabel}${update.app}: ${update.currentBranch} -> ${update.targetBranch} (${update.gitPath})`);
        }
        this.logger.success('自动合并映射写入完成，后续构建将使用目标分支');
        if (skipped.length > 0) {
            this.logger.warn(`以下项目未处理：${skipped.join('；')}`);
        }
    },

    parseFlowDetailUrl(rawUrl) {
        const normalized = this.normalizeString(rawUrl);
        if (!normalized) {
            throw new Error('链接为空');
        }
        let parsed;
        try {
            parsed = new URL(normalized);
        } catch (error) {
            throw new Error('链接格式不正确');
        }
        if (parsed.protocol !== 'https:' || parsed.hostname !== 'vops.hszq8.com' || !parsed.pathname.includes('/app/flow/flow_detail')) {
            throw new Error('仅支持 https://vops.hszq8.com/app/flow/flow_detail 链接');
        }
        const flowType = this.normalizeString(parsed.searchParams.get('flow_type') || parsed.searchParams.get('type'));
        const flowId = this.normalizeString(parsed.searchParams.get('flow_id') || parsed.searchParams.get('id'));
        if (!flowId || !flowType) {
            throw new Error('链接缺少 flow_id 或 flow_type 参数');
        }
        return {
            flowId,
            flowType,
            url: normalized
        };
    },

    async handleGitLabCr() {
        this.logger.step(1, '检查发布单需要CR的项目');
        this.assignProjectOpsFile(getProjectOpsFile());
        await this.initClient(false);
        const flowId = await this.projectOpsFile.read("flow.id");
        const flowType = await this.projectOpsFile.read("flow.flow_type");
        const privateToken = await this.globalOpsFile.read("git_private_token");
        if (StrUtil.isNull(flowId)||StrUtil.isNull(flowType)) {
            throw new Error("请先拉取项目，无法查看发布单");
        }
        if (!privateToken || StrUtil.isNull(privateToken)) {
            throw new Error("请检查 git.private.token");
        }
        this.gitlabClient = newGitLabClient(privateToken, false);
        const appAndBranchData = await this.opsClient.getAppAndBranch(flowId, flowType);
        const crData = await this.opsClient.getCrData(flowId, flowType);
        const processCr = async ({appName, branch, repoId, flowAppId, parentApp}) => {
            const logName = parentApp ? `插件 ${appName} (基座 ${parentApp})` : appName;
            if (StrUtil.isNull(appName) || StrUtil.isNull(branch) || !repoId) {
                this.logger.warn(`${logName} 信息不完整，跳过处理`);
                return;
            }
            const crDataValue = crData?.[appName];
            if (!crDataValue || Object.keys(crDataValue).length === 0) {
                this.logger.info(`${logName} 未进行CR，正在创建MR-CR repoId:${repoId}`);
                if (flowAppId) {
                    await this.opsClient.getCrUrl(flowAppId);
                }
                await this.gitlabClient.mergeRequestsAndCr(repoId, {
                    source_branch: `${branch}`,
                    target_branch: `${branch}-release`,
                    title: `${branch} → ${branch}-release`,
                    labels: '1.CR通过'
                });
                return;
            }
            const webUrl = crDataValue.web_url;
            const mrId = StrUtil.getMrId(webUrl);
            if (StrUtil.isNull(mrId)) {
                this.logger.info(`${logName} MRID为空，正在创建MR-CR repoId:${repoId}`);
                await this.gitlabClient.mergeRequestsAndCr(repoId, {
                    source_branch: `${branch}`,
                    target_branch: `${branch}-release`,
                    title: `${branch} → ${branch}-release`,
                    labels: '1.CR通过'
                });
                return;
            }
            // 如果有，则判断有没有CR标签
            if (CollUtil.isEmptyArray(crDataValue.labels)) {
                this.logger.info(`${logName} 没有CR标签，打CR repoId:${repoId} mrId:${mrId}`);
                await this.gitlabClient.mergeRequestsAndCrByMrId(repoId, mrId, {
                    labels: '1.CR通过'
                });
                return;
            }
            const result = crDataValue.labels.some(label => label.name === "1.CR通过");
            if (result) {
                this.logger.info(`${logName} 已有CR标签 repoId:${repoId} mrId:${mrId}`);
                return;
            }
            this.logger.info(`${logName} 没有CR标签，打CR repoId:${repoId} mrId:${mrId}`);
            await this.gitlabClient.mergeRequestsAndCrByMrId(repoId, mrId, {
                labels: '1.CR通过'
            });
        };

        for (const item of appAndBranchData) {
            await processCr({
                appName: item.app,
                branch: item.name,
                repoId: item.repo_id,
                flowAppId: item.id || item.app_id,
                parentApp: null
            });
            if (Array.isArray(item.plugin_list) && item.plugin_list.length > 0) {
                for (const plugin of item.plugin_list) {
                    await processCr({
                        appName: plugin.app,
                        branch: plugin.name,
                        repoId: plugin.repo_id,
                        flowAppId: plugin.id || plugin.app_id,
                        parentApp: item.app
                    });
                }
            }
        }
        this.logger.success('CR打标已完成');
    },
};
